home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-07-28 | 10.4 KB | 416 lines | [TEXT/PJMM] |
- unit MovableModal;
-
- { This unit implements a MovableModalDialog routine similar to }
- { the Toolbox routine ModalDialog, to be used for movable modal dialogs }
-
- { ANTIĀ© 1993 Merzwaren }
-
- interface
-
- procedure DisableMenuBar (editMenuID: Integer;
- hmnuID: Integer);
- procedure ReEnableMenuBar;
- procedure MovableModalDialog (filterProc: ProcPtr;
- var itemHit: Integer);
-
- implementation
- uses
- Balloons;
-
- const
-
- kSystemMenuThreshold = -16000; { menu IDs <= than this are used by the system }
- kMovableModalEventMask = mDownMask + mUpMask + keyDownMask + keyUpMask + autoKeyMask + updateMask + activMask + app4Mask;
-
- type
-
- MenuEntry = record
- hMenu: MenuHandle;
- leftEdge: Integer;
- end; {MenuEntry}
-
- MenuList = record
- offsetToLastMenu: Integer;
- rightmostEdge: Integer;
- unused: Integer;
- theMenus: array[0..0] of MenuEntry;
- end; {MenuList}
- MenuListPtr = ^MenuList;
- MenuListH = ^MenuListPtr;
-
- MenuBarState = record
- mbsBarEnable: LongInt;
- mbsEditEnable: LongInt;
- mbsEditMenuID: Integer;
- mbsCutItem: Integer;
- mbsCopyItem: Integer;
- mbsPasteItem: Integer;
- end; {MenuBarState}
- MenuBarStatePtr = ^MenuBarState;
- MenuBarStateH = ^MenuBarStatePtr;
-
- var
-
- saveState: Handle;
-
- function HasHelpManager: Boolean;
- var
- response: LongInt;
- begin
- HasHelpManager := (Gestalt(gestaltHelpMgrAttr, response) = noErr) & BTST(response, gestaltHelpMgrPresent);
- end; {HasHelpManager}
-
- procedure ForgetHandle (var h: univ Handle);
- begin
- if (h <> nil) then
- begin
- DisposHandle(h);
- h := nil;
- end;
- end; {ForgetHandle}
-
- function GetMenuList: MenuListH;
- inline
- $2EB8, $0A1C; { move.l MenuList, (sp) }
-
- function GetMenuItemFromKeyEquiv (theMenu: MenuHandle;
- keyEquiv: Char): Integer;
- var
- item, nItems: Integer;
- cmd: Char;
- begin
- GetMenuItemFromKeyEquiv := 0;
- nItems := CountMItems(theMenu);
- for item := 1 to nItems do
- begin
- GetItemCmd(theMenu, item, cmd);
- if (cmd = keyEquiv) then
- begin
- GetMenuItemFromKeyEquiv := item;
- Exit(GetMenuItemFromKeyEquiv);
- end;
- end; { for }
- end; {GetMenuItemFromKeyEquiv}
-
- procedure DisableMenuBar (editMenuID: Integer;
- hmnuID: Integer);
- var
- menuList: MenuListH;
- i, nMenus: Integer;
- theMenu: MenuHandle;
- menuID: Integer;
- menuEnable, barEnable: LongInt;
- theDialog: DialogPtr;
- hasBalloons, needEditMenu: Boolean;
- err: OSErr;
- begin
-
- { determine if the Help manager is available }
- hasBalloons := HasHelpManager;
-
- { determine if the frontmost dialog contains edit fields }
- theDialog := FrontWindow;
- needEditMenu := (theDialog <> nil) & (DialogPeek(theDialog)^.editField >= 0);
-
- { get a handle to the menu list and count the menus }
- menuList := GetMenuList;
- nMenus := menuList^^.offsetToLastMenu div SizeOf(MenuEntry);
-
- { create a parameter block for saving menu bar state information }
- saveState := NewHandleClear(SizeOf(MenuBarState));
- HLock(saveState);
-
- with MenuBarStateH(saveState)^^ do
- begin
-
- barEnable := 0;
-
- { walk the menu list }
- for i := 0 to nMenus - 1 do
- begin
-
- { get menu handle, menu ID and enable flags for this menu }
- theMenu := menuList^^.theMenus[i].hMenu;
- menuID := theMenu^^.menuID;
- menuEnable := theMenu^^.enableFlags;
-
- { do nothing if this is a system menu }
- if (menuID <= kSystemMenuThreshold) then
- Cycle;
-
- { if this is the Edit menu and we need it, do some special processing }
- if ((needEditMenu) and (menuID = editMenuID)) then
- begin
-
- { save edit menu ID }
- mbsEditMenuID := editMenuID;
-
- { save the enable flags for later restoration }
- mbsEditEnable := menuEnable;
-
- { find which items are Cut, Copy and Paste }
- mbsCutItem := GetMenuItemFromKeyEquiv(theMenu, 'X');
- mbsCopyItem := GetMenuItemFromKeyEquiv(theMenu, 'C');
- mbsPasteItem := GetMenuItemFromKeyEquiv(theMenu, 'V');
-
- { enable Cut, Copy and Paste }
- menuEnable := 1 + BSL(1, mbsCutItem) + BSL(1, mbsCopyItem) + BSL(1, mbsPasteItem);
- theMenu^^.enableFlags := menuEnable;
-
- Cycle;
- end; { if menuID = editMenuID }
-
- { if this menu is enabled, disable it and set the corresponding bit in barEnable }
- if (BTST(menuEnable, 0)) then
- begin
- barEnable := BOR(barEnable, BSL(1, i));
- DisableItem(theMenu, 0);
- end;
-
- { remap the help strings for this menu }
- if (hasBalloons) then
- err := HMSetMenuResID(menuID, hmnuID);
-
- end; { for }
-
- mbsBarEnable := barEnable;
-
- end; { with }
-
- { unhighlight the highlighted menu (if any) and redraw the menu bar }
- HiliteMenu(0);
- DrawMenuBar;
-
- { unlock state info parameter block }
- HUnlock(saveState);
-
- end; {DisableMenuBar}
-
- procedure ReEnableMenuBar;
- var
- menuList: MenuListH;
- i, nMenus: Integer;
- theMenu: MenuHandle;
- menuID: Integer;
- hasBalloons: Boolean;
- err: OSErr;
- begin
-
- { sanity check: make sure saveState isn't NIL }
- if (saveState = nil) then
- Exit(ReEnableMenuBar);
-
- { determine if the Help manager is available }
- hasBalloons := HasHelpManager;
-
- { get a handle to the menu list and count the menus }
- menuList := GetMenuList;
- nMenus := menuList^^.offsetToLastMenu div SizeOf(MenuEntry);
-
- HLock(saveState);
-
- with MenuBarStateH(saveState)^^ do
- begin
-
- { walk the menu list }
- for i := 0 to nMenus - 1 do
- begin
-
- { get menu handle and menu ID for this menu }
- theMenu := menuList^^.theMenus[i].hMenu;
- menuID := theMenu^^.menuID;
-
- { do nothing if this is a system menu }
- if (menuID <= kSystemMenuThreshold) then
- Cycle;
-
- { restore old enable state for this menu }
- if (menuID = mbsEditMenuID) then
- theMenu^^.enableFlags := mbsEditEnable
- else if (BTST(mbsBarEnable, i)) then
- EnableItem(theMenu, 0);
-
- { unmap the help strings for this menu }
- if (hasBalloons) then
- err := HMSetMenuResID(menuID, -1);
-
- end; { for }
-
- end; { with }
-
- { forget about the menu bar parameter block }
- HUnlock(saveState);
- ForgetHandle(saveState);
-
- { redraw the menu bar }
- DrawMenuBar;
-
- end; {ReEnableMenuBar}
-
- function CallFilter (dialog: DialogPtr;
- var event: EventRecord;
- var item: Integer;
- filterProc: ProcPtr): Boolean;
- inline
- $205F, { movea.l (sp)+, a0 }
- $4E90; { jsr (a0) }
-
- function GetDABeeper: ProcPtr;
- inline
- $2EB8, $0A9C; { move.l DABeeper, (sp) }
-
- procedure CallBeeper (soundNo: Integer;
- beeperProc: ProcPtr);
- inline
- $205F, { movea.l (sp)+, a0 }
- $4E90; { jsr (a0) }
-
- function DoMenuChoice (theDialog: DialogPtr;
- var theEvent: EventRecord;
- var itemHit: Integer;
- menuChoice: LongInt): Boolean;
- var
- menuID, menuItem: Integer;
- currentEditField, itemType: Integer;
- itemHandle: Handle;
- itemRect: Rect;
- err: OSErr;
- begin
- DoMenuChoice := false;
-
- if (saveState = nil) then
- Exit(DoMenuChoice);
-
- menuID := HiWord(menuChoice);
- menuItem := LoWord(menuChoice);
-
- HLock(saveState);
- with MenuBarStateH(saveState)^^ do
- begin
-
- if (menuID = mbsEditMenuID) then
- begin
-
- { find the current edit field }
- currentEditField := DialogPeek(theDialog)^.editField + 1;
- GetDItem(theDialog, currentEditField, itemType, itemHandle, itemRect);
-
- { if the current edit field is an enabled item, exit from MovableModalDialog loop }
- if (BAND(itemType, itemDisable) = 0) then
- begin
- DoMenuChoice := true;
- itemHit := currentEditField;
- end;
-
- { perform edit operation }
- if (menuItem = mbsCutItem) then
- begin
- DlgCut(theDialog);
- err := ZeroScrap;
- err := TEToScrap;
- end
- else if (menuItem = mbsCopyItem) then
- begin
- DlgCopy(theDialog);
- err := ZeroScrap;
- err := TEToScrap;
- end
- else if (menuItem = mbsPasteItem) then
- DlgPaste(theDialog);
- end;
-
- end; { with }
-
- HUnlock(saveState);
- HiliteMenu(0);
- end; {DoMenuChoice}
-
- function HandleMouseDown (theDialog: DialogPtr;
- var theEvent: EventRecord;
- var itemHit: Integer): Boolean;
- var
- partCode: Integer;
- wind: WindowPtr;
- beeper: ProcPtr;
- dragRect: Rect;
- begin
- HandleMouseDown := false;
-
- { find out where the click went down in }
- partCode := FindWindow(theEvent.where, wind);
-
- { if the click went in the menu bar, just call MenuSelect }
- if (partCode = inMenuBar) then
- begin
- HandleMouseDown := DoMenuChoice(theDialog, theEvent, itemHit, MenuSelect(theEvent.where));
- Exit(HandleMouseDown);
- end;
-
- { if the user clicked somewhere outside the dialog, call the beeper }
- if (not PtInRgn(theEvent.where, WindowPeek(theDialog)^.strucRgn)) then
- begin
- beeper := GetDABeeper;
- if (beeper <> nil) then
- CallBeeper(1, beeper);
- Exit(HandleMouseDown);
- end;
-
- { now, we have to handle the only thing DialogSelect doesn't do for us: dragging }
- if (partCode = inDrag) & (theDialog = wind) then
- begin
- dragRect := GetGrayRgn^^.rgnBBox;
- DragWindow(wind, theEvent.where, dragRect);
- theEvent.what := nullEvent;
- end;
-
- end; {HandleMouseDown}
-
- procedure MovableModalDialog (filterProc: ProcPtr;
- var itemHit: Integer);
- var
- savePort: GrafPtr;
- theDialog: DialogPtr;
- theEvent: EventRecord;
- gotEvent: Boolean;
- begin
- itemHit := 0;
-
- { get a pointer to the frontmost window (which should be our movable dialog) }
- theDialog := FrontWindow;
- if (theDialog = nil) then
- Exit(MovableModalDialog);
-
- { set thePort to the dialog }
- GetPort(savePort);
- SetPort(theDialog);
-
- { modal dialog event loop }
- repeat
-
- { yield time to other processes and retrieve next event from the queue }
- gotEvent := WaitNextEvent(kMovableModalEventMask, theEvent, 0, nil);
-
- { the filter proc is the first one to get a chance to process the event }
- if (filterProc <> nil) & CallFilter(theDialog, theEvent, itemHit, filterProc) then
- Leave;
-
- { then comes our own processing of clicks in the menu bar and in the drag bar }
- if (theEvent.what = mouseDown) & HandleMouseDown(theDialog, theEvent, itemHit) then
- Leave;
-
- { and our processing of keyboard equivalents for the Edit items }
- if (theEvent.what = keyDown) & (BAND(theEvent.modifiers, cmdKey) <> 0) & DoMenuChoice(theDialog, theEvent, itemHit, MenuKey(CHR(BAND(theEvent.message, charCodeMask)))) then
- Leave;
-
- { finally we let the Toolbox do its own thing }
- if IsDialogEvent(theEvent) & DialogSelect(theEvent, theDialog, itemHit) then
- Leave;
-
- until false;
-
- { restore the old port }
- SetPort(savePort);
-
- end; {MovableModalDialog}
-
- end.